﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Reflection;
using System.Text;
using YAPL.Language.Ast.Utils;

namespace YAPL.Language.Ast {
	public class FunctionCallExpression : Expression {
		private readonly string _methodName;
		private readonly List<Expression> _arguments;
		private readonly Expression _callingObject;
		public FunctionCallExpression(ExpressionType nodeType, Type type, string methodName,
				List<Expression> arguments, Expression callingObject)
			: base(nodeType, type) {
			_methodName = methodName;
			_arguments = arguments;
			_callingObject = callingObject;
		}

		public FunctionCallExpression(ExpressionType nodeType, Type type, bool canRead, bool canWrite, string methodName,
				List<Expression> arguments, Expression callingObject)
			: base(nodeType, type, canRead, canWrite) {
			_methodName = methodName;
			_arguments = arguments;
			_callingObject = callingObject;
		}

		public string MethodName {
			get { return _methodName; }
		}

		[Descendant(AstVisit.BeforeCurrent, Priority = 0)]
		public List<Expression> Arguments {
			get { return _arguments; }
		}

		[Descendant(AstVisit.BeforeCurrent, Priority = 1)]
		public Expression CallingObject {
			get { return _callingObject; }
		}

		public override bool NodeEquals(Expression other) {
			if (other is FunctionCallExpression) {
				var otherMethodName = (other as FunctionCallExpression)._methodName;
				var otherArgCount = (other as FunctionCallExpression)._arguments.Count;
				return _methodName.Equals(otherMethodName) && _arguments.Count.Equals(otherArgCount);
			}
			return false;
		}

		public override bool RewriteChild(Expression child, Expression newExpression) {
			var rewritten = false;
			for (var i = 0; i < _arguments.Count; i++) {
				if (ReferenceEquals(_arguments[i], child)) {
					_arguments[i] = newExpression;
					rewritten = true;
				}
			}
			return rewritten;
		}
	}
}
